// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <string>
#include <vector>

#include "coin2/exchange/base/order/order.h"

namespace coin2::strategy::order_executor {

class WorkingOrderState {
 public:
  enum class AcceptPolicyType {
    UNKNOWN_FILTER_TYPE = 0,
    SELL_ON_THE_FLY_ORDERS = 1,
    SELL_WORKING_ORDERS = 2,
    SELL_CANCEL_ON_THE_FLY_ORDERS = 3,
    SELL_ORDERS = 4,
    BUY_ON_THE_FLY_ORDERS = 5,
    BUY_WORKING_ORDERS = 6,
    BUY_CANCEL_ON_THE_FLY_ORDERS = 7,
    BUY_ORDERS = 8
  };

 public:
  using OrderContext = exchange::base::order::OrderContext;
  using OrderList = std::vector<const OrderContext*>;
  using IOrderSubsystem = exchange::base::order::IOrderSubsystem;
  using AcceptPolicy = std::function<bool(const OrderContext*, AcceptPolicyType)>;

 public:
  WorkingOrderState(const std::string native_symbol, IOrderSubsystem* os, AcceptPolicy ap);
  WorkingOrderState(const std::string native_symbol, IOrderSubsystem* os);

  const std::string& native_product() { return native_product_; }

  const auto& GetSellWorkingOrOnTheFlyOrders() {
    return sell_working_or_on_the_fly_orders_;
  }
  const auto& GetSellOnTheFlyOrders() { return sell_on_the_fly_orders_; }
  const auto& GetSellWorkingOrders() { return sell_working_orders_; }
  const auto& GetSellCancelOnTheFlyOrders() { return sell_cancel_on_the_fly_orders_; }

  const auto& GetBuyWorkingOrOnTheFlyOrders() {
    return buy_working_or_on_the_fly_orders_;
  }
  const auto& GetBuyOnTheFlyOrders() { return buy_on_the_fly_orders_; }
  const auto& GetBuyWorkingOrders() { return buy_working_orders_; }
  const auto& GetBuyCancelOnTheFlyOrders() { return buy_cancel_on_the_fly_orders_; }

  auto GetSellUnackCount() { return sell_on_the_fly_orders_.size(); }
  auto GetSellUnackQty() const { return std::abs(sell_on_the_fly_potential_); }

  auto GetBuyUnackCount() { return buy_on_the_fly_orders_.size(); }
  auto GetBuyUnackQty() const { return std::abs(buy_on_the_fly_potential_); }

  auto GetSellCancelUnackCount() { return sell_cancel_on_the_fly_orders_.size(); }
  auto GetBuyCancelUnackCount() { return buy_cancel_on_the_fly_orders_.size(); }

  const OrderList& GetBuyOrders() { return buy_orders_; }
  const OrderList& GetSellOrders() { return sell_orders_; }

  void ResetOrderState();
  void UpdateOrderState();

  double GetSellPotential() const { return sell_potential_; }
  double GetBuyPotential() const { return buy_potential_; }

  auto GetOrderContextByProcOrderId(int64_t proc_order_id) -> const OrderContext* {
    for (auto order : os_->order_manager()->GetAllWorkingOrders()) {
      if (order->proc_order_id() == proc_order_id) {
        return order;
      }
    }
    return nullptr;
  }

 private:
  const std::string native_product_;
  IOrderSubsystem* os_;

  OrderList sell_working_or_on_the_fly_orders_;
  OrderList sell_on_the_fly_orders_;
  OrderList sell_working_orders_;
  OrderList sell_cancel_on_the_fly_orders_;
  OrderList sell_orders_;
  double sell_on_the_fly_potential_;
  double sell_working_potential_;
  double sell_cancel_on_the_fly_potential_;
  double sell_potential_;

  OrderList buy_working_or_on_the_fly_orders_;
  OrderList buy_on_the_fly_orders_;
  OrderList buy_working_orders_;
  OrderList buy_cancel_on_the_fly_orders_;
  OrderList buy_orders_;
  double buy_on_the_fly_potential_;
  double buy_working_potential_;
  double buy_cancel_on_the_fly_potential_;
  double buy_potential_;
  AcceptPolicy accept_policy_;
};
}  // namespace coin2::strategy::order_executor
